/* vim:set noet ts=4: */
/** 
 * scim-python
 * 
 * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA  02111-1307  USA
 *
 * $Id: $
 */
#include "scim-python.h"

extern PyTypeObject PyIMEngineType;

struct PyIMEngineObject {
	PyListObject list;
	/* Type-specific fields go here. */
	PyIMEngine *engine;
};

#define PY_CALL(fun) ({								\
	PyObject *pValue = NULL;						\
	PyObject *pFunc = NULL;							\
	pFunc = PyObject_GetAttrString(this->self, fun);\
	if (pFunc != NULL) {							\
		pValue = PyObject_CallObject (pFunc, NULL);	\
		Py_DECREF (pFunc);							\
	}												\
	pValue;})

#define PY_CALL_1(fun, arg1) ({						\
	PyObject *pValue = NULL;						\
	PyObject *pFunc = NULL;							\
	PyObject *pArgs = NULL;							\
	pFunc = PyObject_GetAttrString(this->self, fun);\
	if (pFunc != NULL) {							\
		pArgs = PyTuple_New (1);					\
		PyTuple_SetItem (pArgs, 0, arg1);			\
		pValue = PyObject_CallObject (pFunc, pArgs);\
		Py_DECREF (pFunc);							\
		Py_DECREF (pArgs);							\
	}												\
	pValue;})

#define PY_CHECK_RET(v)							\
	if (v == NULL) {							\
		PyErr_Print ();							\
		return;									\
	}

#define PY_CHECK_RET_VAL(v, val)				\
	if (v == NULL) {							\
		PyErr_Print ();							\
		return val;								\
	}

bool 
PyIMEngine::process_key_event (const KeyEvent &key)
{
	PyObject *pValue;
	
	bool result = false;
	
	pValue = PY_CALL_1("process_key_event", PyKeyEvent_New (key));

	PY_CHECK_RET_VAL (pValue, false);
	
	result = (pValue == Py_True); 
	Py_DECREF(pValue);
	
	return result;
}

PyObject *
PyIMEngine::py_process_key_event (PyIMEngineObject *self, PyObject *args)
{
	PyErr_SetString (PyExc_NotImplementedError, "process_key_event is not implemented!");
	return NULL;
}


void
PyIMEngine::move_preedit_caret (unsigned int pos)
{
	PyObject *pValue;
	
	pValue = PY_CALL_1 ("move_preedit_caret", PyInt_FromLong ((unsigned long)pos));
	PY_CHECK_RET (pValue);
	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_move_preedit_caret (PyIMEngineObject *self, PyObject *args)
{
	unsigned int pos;

	if (!PyArg_ParseTuple(args, "I:move_preedit_caret", &pos))
		return NULL;

	self->engine->IMEngineInstanceBase::move_preedit_caret (pos);

	Py_INCREF(Py_None);
	return Py_None;
	
}

void
PyIMEngine::select_candidate (unsigned int index)
{
	PyObject *pValue;
	
	pValue = PY_CALL_1 ("select_candidate", PyInt_FromLong ((unsigned long)index));
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_select_candidate (PyIMEngineObject *self, PyObject *args)
{
	unsigned int index;

	if (!PyArg_ParseTuple(args, "I:select_candidate", &index))
		return NULL;

	self->engine->IMEngineInstanceBase::select_candidate (index);

	Py_INCREF(Py_None);
	return Py_None;
	
}

void
PyIMEngine::update_lookup_table_page_size (unsigned int page_size)
{
	PyObject *pValue;
	
	pValue = PY_CALL_1 ("update_lookup_table_page_size", PyInt_FromLong ((unsigned long)page_size));
	PY_CHECK_RET (pValue);

	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_update_lookup_table_page_size (PyIMEngineObject *self, PyObject *args)
{
	unsigned int page_size;

	if (!PyArg_ParseTuple(args, "I:update_lookup_table_page_size", &page_size))
		return NULL;

	self->engine->IMEngineInstanceBase::move_preedit_caret (page_size);

	Py_INCREF(Py_None);
	return Py_None;
	
}

void
PyIMEngine::lookup_table_page_up ()
{
	PyObject *pValue;
	pValue = PY_CALL ("lookup_table_page_up");
	PY_CHECK_RET (pValue);
	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_lookup_table_page_up (PyIMEngineObject *self)
{
	self->engine->IMEngineInstanceBase::lookup_table_page_up ();

	Py_INCREF(Py_None);
	return Py_None;	
}

void
PyIMEngine::lookup_table_page_down ()
{
	PyObject *pValue;

	pValue = PY_CALL ("lookup_table_page_down");
	PY_CHECK_RET (pValue);

	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_lookup_table_page_down (PyIMEngineObject *self)
{
	self->engine->IMEngineInstanceBase::lookup_table_page_down ();

	Py_INCREF(Py_None);
	return Py_None;	
}

void
PyIMEngine::reset ()
{
	PyObject *pValue;

	pValue = PY_CALL ("reset");
	PY_CHECK_RET (pValue);

	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_reset (PyIMEngineObject *self)
{
	self->engine->IMEngineInstanceBase::reset ();

	Py_INCREF(Py_None);
	return Py_None;	
}

void
PyIMEngine::focus_in ()
{
	PyObject *pValue;

	pValue = PY_CALL ("focus_in");
	PY_CHECK_RET (pValue);

	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_focus_in (PyIMEngineObject *self)
{
	self->engine->IMEngineInstanceBase::focus_in ();

	Py_INCREF(Py_None);
	return Py_None;	
}

void
PyIMEngine::focus_out ()
{
	PyObject *pValue;

	pValue = PY_CALL ("focus_out");
	PY_CHECK_RET (pValue);

	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_focus_out (PyIMEngineObject *self)
{
	self->engine->IMEngineInstanceBase::focus_out ();

	Py_INCREF(Py_None);
	return Py_None;	
}

void
PyIMEngine::trigger_property (const String &property)
{
	PyObject *pValue;

	pValue = PY_CALL_1 ("trigger_property", PyString_FromString (property.c_str ()));
	PY_CHECK_RET (pValue);

	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_trigger_property (PyIMEngineObject *self, PyObject *args)
{
	char *property;

	if (!PyArg_ParseTuple(args, "s:trigger_property", &property))
		return NULL;

	self->engine->IMEngineInstanceBase::trigger_property (String(property));

	Py_INCREF(Py_None);
	return Py_None;
	
}

void
PyIMEngine::process_helper_event (const String &helper_uuid, const Transaction &trans)
{
	//IMEngineInstanceBase::process_helper_event (helper_uuid, trans);
}

PyObject *
PyIMEngine::py_process_helper_event (PyIMEngineObject *self, PyObject *args)
{
	// TODO: 
	char *helper_uuid;
	PyObject *trans;

	if (!PyArg_ParseTuple(args, "sO:process_helper_event", &helper_uuid, &trans))
		return NULL;

	//self->engine->IMEngineInstanceBase::update_client_capabilities (cap);

	Py_INCREF(Py_None);
	return Py_None;
	
}

void
PyIMEngine::update_client_capabilities (unsigned int cap)
{
	PyObject *pValue;

	pValue = PY_CALL_1 ("update_client_capabilities", PyInt_FromLong ((unsigned long)cap));
	PY_CHECK_RET (pValue);

	Py_DECREF (pValue);
}

PyObject *
PyIMEngine::py_update_client_capabilities (PyIMEngineObject *self, PyObject *args)
{
	unsigned int cap;

	if (!PyArg_ParseTuple(args, "I:update_client_capabilities", &cap))
		return NULL;
	self->engine->IMEngineInstanceBase::update_client_capabilities (cap);

	Py_INCREF(Py_None);
	return Py_None;
	
}


void 
PyIMEngine::reload_config (const ConfigPointer &config)
{
	PyObject *pFunc = NULL;
	PyObject *pValue = NULL;
	PyObject *pArgs = NULL;

	pFunc = PyObject_GetAttrString(this->self, "reload_config");
	if (pFunc == NULL)
		goto _failed_out;

	pArgs = Py_BuildValue ("(O)", this->config);
	if (pArgs == NULL)
		goto _failed_out;

	pValue = PyObject_CallObject (pFunc, pArgs);
	if (pValue == NULL)
		goto _failed_out;

	Py_DECREF (pArgs);
	Py_DECREF (pFunc);
	Py_DECREF (pValue);
	
	return;

_failed_out:
	PyErr_Print ();
	Py_XDECREF (pArgs);
	Py_XDECREF (pFunc);
	Py_XDECREF (pValue);
}

IMEngineInstanceBase *
PyIMEngine::from_pyobject (PyObject *object)
{
	PyIMEngineObject *self = (PyIMEngineObject *)object;
	return (IMEngineInstanceBase *)self->engine;
}

PyObject *
PyIMEngine::py_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	PyIMEngine *self;

	self = (PyIMEngine *)type->tp_alloc(type, 0);
	return (PyObject *)self;
}

int
PyIMEngine::py_init(PyIMEngineObject *self, PyObject *args, PyObject *kwds)
{
	PyObject *factory;
	PyObject *config;
	char *encoding;
	int id;
	
	if (!PyArg_ParseTuple(args, "OOsi:__init__", &factory, &config, &encoding, &id)) {
		PyErr_Print ();
		return -1;
	}

	self->engine = new PyIMEngine ((PyObject *)self, 
								factory,
								config,
								String(encoding), id);
	return 0;
}

PyObject *
PyIMEngine::py_show_preedit_string (PyIMEngineObject *self)
{
	self->engine->show_preedit_string ();

	Py_INCREF(Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_show_aux_string (PyIMEngineObject *self)
{
	self->engine->show_aux_string ();

	Py_INCREF(Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_show_lookup_table (PyIMEngineObject *self)
{
	self->engine->show_lookup_table ();

	Py_INCREF(Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_hide_preedit_string (PyIMEngineObject *self)
{
	self->engine->hide_preedit_string ();

	Py_INCREF(Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_hide_aux_string (PyIMEngineObject *self)
{
	self->engine->hide_aux_string ();

	Py_INCREF(Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_hide_lookup_table (PyIMEngineObject *self)
{
	self->engine->hide_lookup_table ();

	Py_INCREF(Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_update_preedit_caret (PyIMEngineObject *self, PyObject *args)
{
	int caret;
	if (!PyArg_ParseTuple(args, "i:update_preedit_caret", &caret))
			return NULL;
	self->engine->update_preedit_caret (caret);

	Py_INCREF(Py_None);
	return Py_None;	
}
/*
void update_preedit_string (const WideString	&str,
							const AttributeList &attrs = AttributeList ());
*/
PyObject *
PyIMEngine::py_update_preedit_string (PyIMEngineObject *self, PyObject *args)
{
	Py_UNICODE *str = NULL;
	PyObject *pAttrs = NULL;
	AttributeList attrs;
	
	if (!PyArg_ParseTuple(args, "u|O:update_preedit_string", &str, &pAttrs))
		return NULL;

	self->engine->update_preedit_string (WideString ((wchar_t *)str), 
								Attributes_FromTupleOrList (pAttrs));
	
	Py_INCREF(Py_None);
	return Py_None;
	
}

/*
 * void update_aux_string (const WideString	&str,
 * 						   const AttributeList &attrs = AttributeList ());
 */
PyObject *
PyIMEngine::py_update_aux_string (PyIMEngineObject *self, PyObject *args)
{
	Py_UNICODE *str = NULL;
	PyObject *pAttrs = NULL;
	AttributeList attrs;
	
	if (!PyArg_ParseTuple(args, "u|O:update_aux_string", &str, &pAttrs))
		return NULL;
	
	self->engine->update_aux_string (WideString ((wchar_t *)str),
								Attributes_FromTupleOrList(pAttrs));
	
	Py_INCREF(Py_None);
	return Py_None;
}

/*
 * void update_lookup_table (const LookupTable &table);
 */
PyObject *
PyIMEngine::py_update_lookup_table (PyIMEngineObject *self, PyObject *args)
{

	PyObject *lookup_table = NULL;
	
	if (!PyArg_ParseTuple(args, "O:update_lookup_table", &lookup_table))
		return NULL;
		
	self->engine->update_lookup_table (PyLookupTable::from_pyobject (lookup_table));
	
	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void commit_string (const WideString &str);
 */
PyObject *
PyIMEngine::py_commit_string (PyIMEngineObject *self, PyObject *args)
{
	Py_UNICODE *str = NULL;
	
	if (!PyArg_ParseTuple(args, "u:commit_string", &str))
		return NULL;
	
	self->engine->commit_string (WideString ((wchar_t *)str));
	
	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void forward_key_event (const KeyEvent &key);
 */
PyObject *
PyIMEngine::py_forward_key_event (PyIMEngineObject *self, PyObject *args)
{
	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void register_properties (const PropertyList &properties);
 */
PyObject *
PyIMEngine::py_register_properties (PyIMEngineObject *self, PyObject *args)
{
	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void update_property (const Property &property);
 */
PyObject *
PyIMEngine::py_update_properties (PyIMEngineObject *self, PyObject *args)
{
	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void beep ();
 */
PyObject *
PyIMEngine::py_beep (PyIMEngineObject *self)
{
	self->engine->beep ();

	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void start_helper (const String &helper_uuid);
 */
PyObject *
PyIMEngine::py_start_helper (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple(args, "s:start_helper", &str))
		return NULL;
	
	self->engine->start_helper (String (str));

	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void stop_helper (const String &helper_uuid);
 */
PyObject *
PyIMEngine::py_stop_helper (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple(args, "s:stop_helper", &str))
		return NULL;
	
	self->engine->stop_helper (String (str));

	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * void send_helper_event (const String &helper_uuid, const Transaction &trans);
 */
PyObject *
PyIMEngine::py_send_helper_event (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple(args, "s:send_helper_event", &str))
		return NULL;
	
	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * bool get_surrounding_text (WideString &text, 
 * 							int &cursor, i
 * 							nt maxlen_before = -1, 
 * 							int maxlen_after = -1);
 */
PyObject *
PyIMEngine::py_get_surrounding_text (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple(args, "s:get_surrounding_text", &str))
		return NULL;
	
	Py_INCREF(Py_None);
	return Py_None;	
}

/*
 * bool delete_surrounding_text (int offset, int len);
 */
PyObject *
PyIMEngine::py_delete_surrounding_text (PyIMEngineObject *self, PyObject *args)
{
	int offset;
	int len;

	if (!PyArg_ParseTuple(args, "ii:delete_surrounding_text", &offset, &len))
		return NULL;
	
	self->engine->delete_surrounding_text (offset, len);
	
	Py_INCREF(Py_None);
	return Py_None;	
}

PyMethodDef
PyIMEngine::py_methods[] = { 
		{	"show_preedit_string", (PyCFunction)PyIMEngine::py_show_preedit_string, METH_NOARGS,
			"Show preedit string" 
		}, 
		{	"show_aux_string", (PyCFunction)PyIMEngine::py_show_aux_string, METH_NOARGS,
			"Show aux string" 
		}, 
		{	"show_lookup_table", (PyCFunction)PyIMEngine::py_show_lookup_table, METH_NOARGS,
			"Show lookup table" 
		},
		{	"hide_preedit_string", (PyCFunction)PyIMEngine::py_hide_preedit_string, METH_NOARGS,
			"Hide preedit string" 
		}, 
		{	"hide_aux_string", (PyCFunction)PyIMEngine::py_hide_aux_string, METH_NOARGS,
			"Hide aux string" 
		}, 
		{	"hide_lookup_table", (PyCFunction)PyIMEngine::py_hide_lookup_table, METH_NOARGS,
			"Hide lookup table" 
		},		
		{	"update_preedit_caret", (PyCFunction)PyIMEngine::py_update_preedit_caret, METH_VARARGS,
			"Update preedit caret" 
		},
		{	"update_preedit_string", (PyCFunction)PyIMEngine::py_update_preedit_string, METH_VARARGS,
			"Update preedit string" 
		},
		{	"update_aux_string", (PyCFunction)PyIMEngine::py_update_aux_string, METH_VARARGS,
			"Update aux string" 
		}, 
		{	"update_lookup_table", (PyCFunction)PyIMEngine::py_update_lookup_table, METH_VARARGS,
			"Update lookup table" 
		},
		{	"commit_string", (PyCFunction)PyIMEngine::py_commit_string, METH_VARARGS,
			"commit string" 
		}, 
		{	"forward_key_event", (PyCFunction)PyIMEngine::py_forward_key_event, METH_VARARGS,
			"forward key event" 
		}, 
		{	"register_properties", (PyCFunction)PyIMEngine::py_register_properties, METH_VARARGS,
			"register properties" 
		}, 
		{	"update_properties", (PyCFunction)PyIMEngine::py_update_properties, METH_VARARGS,
			"update properties" 
		},
		{	"beep", (PyCFunction)PyIMEngine::py_beep, METH_NOARGS,
			"beep" 
		}, 
		{	"start_helper", (PyCFunction)PyIMEngine::py_start_helper, METH_VARARGS,
			"start helper" 
		}, 
		{	"stop_helper", (PyCFunction)PyIMEngine::py_stop_helper, METH_VARARGS,
			"stop helper" 
		}, 
		{	"send_helper_event", (PyCFunction)PyIMEngine::py_send_helper_event, METH_VARARGS,
			"send event to a helper" 
		}, 
		{	"get_surrounding_text", (PyCFunction)PyIMEngine::py_get_surrounding_text, METH_VARARGS,
			"get surrounding text" 
		}, 
		{	"delete_surrounding_text", (PyCFunction)PyIMEngine::py_delete_surrounding_text, METH_VARARGS,
			"delete surrounding text" 
		},		
		{	"process_key_event", (PyCFunction)PyIMEngine::py_process_key_event, METH_VARARGS,
			"process key event" 
		},		
		{	"move_preedit_caret", (PyCFunction)PyIMEngine::py_move_preedit_caret, METH_VARARGS,
			"move preedit caret" 
		},		
		{	"select_candidate", (PyCFunction)PyIMEngine::py_select_candidate, METH_VARARGS,
			"select candidate" 
		},
		{	"update_lookup_table_page_size", (PyCFunction)PyIMEngine::py_update_lookup_table_page_size, METH_VARARGS,
			"update lookup table page size" 
		},
		{	"lookup_table_page_up", (PyCFunction)PyIMEngine::py_lookup_table_page_up, METH_NOARGS,
			"lookup table page up" 
		},
		{	"lookup_table_page_down", (PyCFunction)PyIMEngine::py_lookup_table_page_down, METH_NOARGS,
			"lookup table page down" 
		},
		{	"reset", (PyCFunction)PyIMEngine::py_reset, METH_NOARGS,
			"reset" 
		},
		{	"focus_in", (PyCFunction)PyIMEngine::py_focus_in, METH_NOARGS,
			"focus in" 
		},
		{	"focus_out", (PyCFunction)PyIMEngine::py_focus_out, METH_NOARGS,
			"focus_out" 
		},	
		{	"trigger_property", (PyCFunction)PyIMEngine::py_trigger_property, METH_VARARGS,
			"trigger property" 
		},
		{	"process_helper_event", (PyCFunction)PyIMEngine::py_process_helper_event, METH_VARARGS,
			"process_helper_event" 
		},
		{	"update_client_capabilities", (PyCFunction)PyIMEngine::py_update_client_capabilities, METH_VARARGS,
			"update client capabilities" 
		},
		{ NULL }
};

PyTypeObject PyIMEngineType = {
	PyObject_HEAD_INIT(NULL)
	0,						 				/*ob_size*/
	"scim.IMEngine", 			/*tp_name*/
	sizeof(PyIMEngineObject), 							/*tp_basicsize*/
	0,						 				/*tp_itemsize*/
	0,										/*tp_dealloc*/
	0,			  						/*tp_print*/
	0,						 				/*tp_getattr*/
	0,										/*tp_setattr*/
	0,										/*tp_compare*/
	0,			  						/*tp_repr*/
	0,										/*tp_as_number*/
	0,			  						/*tp_as_sequence*/
	0,										/*tp_as_mapping*/
	0,			  						/*tp_hash */
	0,										/*tp_call*/
	0,		  							/*tp_str*/
	0,					   				/*tp_getattro*/
	0,										/*tp_setattro*/
	0,					 					/*tp_as_buffer*/
	Py_TPFLAGS_DEFAULT | 
	Py_TPFLAGS_BASETYPE,					/*tp_flags*/
	"IMEngineInstanceBase objects",		 /* tp_doc */
	0,					   /* tp_traverse */
	0,					   /* tp_clear */
	0,					   /* tp_richcompare */
	0,					   /* tp_weaklistoffset */
	0,					   /* tp_iter */
	0,					   /* tp_iternext */
	PyIMEngine::py_methods,			 /* tp_methods */
	0,			 /* tp_members */
	0,						 /* tp_getset */
	0,						 /* tp_base */
	0,						 /* tp_dict */
	0,						 /* tp_descr_get */
	0,						 /* tp_descr_set */
	0,						 /* tp_dictoffset */
	(initproc)PyIMEngine::py_init,	  /* tp_init */
	0,						 /* tp_alloc */
	PyIMEngine::py_new,				 /* tp_new */	
};




PyIMEngine::PyIMEngine(
		PyObject *self,
		PyObject 			*factory,
		PyObject			*config,
		const String		&encoding,
		int				  	id)
  : IMEngineInstanceBase (PyIMEngineFactory::from_pyobject(factory), 
	encoding, id), 
	self (self), 
	factory (factory),
	config (config)
{
	Py_INCREF (self);
	Py_INCREF (factory);
	Py_INCREF (config);
	
	reload_signal_connection = 
		PyConfig_from_pyobject (config)->signal_connect_reload (slot (this, &PyIMEngine::reload_config));
}

PyIMEngine::~PyIMEngine()
{
	reload_signal_connection.disconnect ();

	Py_XDECREF (self);
	Py_XDECREF (config);
	Py_XDECREF (factory);
}

void init_engine (PyObject *module)
{
	if (PyType_Ready(&PyIMEngineType) < 0)
		return;
	
	Py_INCREF(&PyIMEngineType);
	PyModule_AddObject(module, "IMEngine", (PyObject *)&PyIMEngineType);	
}

